package com.yanyeori.framework.core.util;

import com.yanyeori.framework.core.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;

/**
 * 导出CSV文件
 *
 * @author chenkuan 2019/11/11
 */
@Slf4j
public class ExportCSV<T> {

    /**
     * CSV文件生成
     *
     * @param title    文件名
     * @param headers  头部标题行
     * @param renders  表格标题对应的字段集合
     * @param dataList 数据
     * @param response 响应
     */
    public void export(String title, List<String> headers, List<String> renders, Collection<T> dataList, HttpServletResponse response) {
        BufferedWriter csvWriter = null;
        try {
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            String fileName = title + ".csv";
            fileName = HttpUtil.encodeUrl(fileName).replaceAll("\\+", " "); //解决编码后空格变 + 号
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            // 创建BufferedWriter写入流
            csvWriter = new BufferedWriter(new OutputStreamWriter(response.getOutputStream(), StandardCharsets.UTF_8));
            // 添加BOM头，解决微软excel中文乱码
            csvWriter.write(new String(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}));
            // 写入文件头部
            writeRow(headers, csvWriter);
            // 写入文件内容
            for (T data : dataList) {
                writeRow(data, renders, csvWriter);
            }
            csvWriter.flush();
        } catch (Exception e) {
            throw new ServiceException(e, "Create CSV Exception");
        } finally {
            if (csvWriter != null) {
                try {
                    csvWriter.close();
                } catch (IOException e) {
                    log.error("CSVWriter Stream Close Exception", e);
                }
            }
        }
    }

    /**
     * 写一行数据到头部
     *
     * @param headers   数据
     * @param csvWriter 文件写入流
     */
    private void writeRow(List<String> headers, BufferedWriter csvWriter) throws IOException {
        // 写入标题
        StringBuilder builder = new StringBuilder();
        for (String header : headers) {
            builder.append("\"").append(header).append("\",");
        }
        csvWriter.write(builder.toString());
        csvWriter.newLine();
    }

    /**
     * 写一行对象数据
     *
     * @param t         数据对象
     * @param renders   表格标题对应的字段集合
     * @param csvWriter 文件写入流
     */
    private void writeRow(T t, List<String> renders, BufferedWriter csvWriter) throws IOException, NoSuchFieldException, IllegalAccessException {
        // 写入内容
        StringBuilder builder = new StringBuilder();
        Object value;
        for (String fieldStr : renders) {
            Field field = t.getClass().getDeclaredField(fieldStr);
            field.setAccessible(true);
            value = field.get(t);
            boolean isNumeric = false;
            if (value != null && Number.class.isAssignableFrom(field.getType())) {
                value = new BigDecimal(value.toString()).stripTrailingZeros().toPlainString();
            } else if (value != null && isNumeric(value.toString())) {
                //解决纯数字在excel中打开数字前面的0丢失
                isNumeric = true;
            }
            builder.append("\"");
            builder.append(value == null ? "" : value);
            if (isNumeric) {
                builder.append("\t");
            }
            builder.append("\",");
        }
        csvWriter.write(builder.toString());
        csvWriter.newLine();
    }

    private static boolean isNumeric(String str) {
        Pattern pattern = Pattern.compile("[0-9]*");
        return pattern.matcher(str).matches();
    }
}
